﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using Finance.Annotations;
using Finance.Controllers;
using Finance.Data.Entities;

namespace Finance.ViewModels
{
	internal class DocumentViewModelBase : INotifyPropertyChanged
	{
		private readonly IDocumentBaseController _controller;
		public event PropertyChangedEventHandler PropertyChanged;
		protected decimal _decimalAmount;
		protected bool _isAmountValid;
		protected bool _autoCalculateDocumentTotalAmount;
		protected string _amount;
		private DateTime _docDate;
		private string _subTypeName;
		private string _contractorName;

		protected DocumentViewModelBase(IDocumentBase document, IDocumentBaseController controller)
		{
			_controller = controller;
			Document = document;

			SubTypeName = document.SubTypeName;
			Description = document.Description;
			DocDate = document.DocDate;
			Amount = document.Amount != 0 ? document.Amount.ToString("F", CultureInfo.InvariantCulture) : string.Empty;
			Contractor = Document.Contractor;
			ContractorName = Document.Contractor == null ? string.Empty : Document.Contractor.Name;
			_autoCalculateDocumentTotalAmount = Amount == string.Empty;
		}

		public IDocumentBase Document { get; private set; }
		
		public IEnumerable<string> DocumentSubTypes
		{
			get { return _controller.GetDocumentSubTypesNames(Document.DocumentType); }
		}

		public IList<IContractor> Contractors
		{
			get { return _controller.GetContractors(); }
		}

		public string SubTypeName
		{
			get { return _subTypeName; }
			set
			{
				if (value == _subTypeName) return;
				_subTypeName = value;
				RaisePropertyChanged("SubTypeName");
			}
		}

		public string Description { get; set; }

		public DateTime DocDate
		{
			get { return _docDate; }
			set
			{
				if (value.Equals(_docDate)) return;
				_docDate = value;
				RaisePropertyChanged("DocDate");
			}
		}

		public string Amount
		{
			get { return _amount; }
			set
			{
				if (!SetAmount(value)) return;

				try
				{
					_autoCalculateDocumentTotalAmount = _decimalAmount == 0m;
				}
				catch
				{
					_autoCalculateDocumentTotalAmount = false;
				}
			}
		}

		protected bool SetAmount(string value)
		{
			if (_amount == value)
				return false;
			_amount = value;

			try
			{
				var strAmount = Amount
					.Replace(".", CultureInfo.CurrentCulture.NumberFormat.CurrencyDecimalSeparator)
					.Replace(",", CultureInfo.CurrentCulture.NumberFormat.CurrencyDecimalSeparator);

				_decimalAmount = Decimal.Parse(strAmount, NumberStyles.Currency);
				IsAmountValid = true;
			}
			catch
			{
				_decimalAmount = 0;
				IsAmountValid = false;
			}

			RaisePropertyChanged("Amount");
			return true;
		}

		public bool IsAmountValid
		{
			get { return _isAmountValid; }
			set
			{
				if (value.Equals(_isAmountValid)) return;
				_isAmountValid = value;
				RaisePropertyChanged("IsAmountValid");
			}
		}

		public IContractor Contractor { get; set; }
		public string ContractorName
		{
			get { return _contractorName; }
			set
			{
				if (value == _contractorName) return;
				_contractorName = value;
				RaisePropertyChanged("ContractorName");
			}
		}

		[NotifyPropertyChangedInvocator]
		protected virtual void RaisePropertyChanged(string propertyName)
		{
			if (PropertyChanged != null)
				PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
		}

		public virtual void ApplyChangesToModel()
		{
			Document.Amount = _decimalAmount;
			Document.DocDate = DocDate;
			Document.Description = Description;
			Document.SubTypeName = SubTypeName;

			// User can type name of exist contractor
			if (Contractor == null && !string.IsNullOrEmpty(ContractorName))
			{
				Contractor = Contractors.FirstOrDefault(c => c.Name == ContractorName)
							 ?? _controller.CreateContractor(ContractorName);
			}

			Document.Contractor = Contractor;
		}
	}
}
